// 2-2 动态内存-数组的动态内存分配

/**
 * 了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分：

    栈：在函数内部声明的所有变量都将占用栈内存。
    堆：这是程序中未使用的内存，在程序运行时可用于动态分配内存。

 * 很多时候，您无法提前预知需要多少内存来存储某个定义变量中的特定信息，所需内存的大小需要在运行时才能确定。

 * 在 C++ 中，您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存，这会返回所分配的空间地址。这种运算符即 new 运算符。

 * 如果您不再需要动态分配的内存空间，可以使用 delete 运算符，删除之前由 new 运算符分配的内存。
 *
 * 
 * 数组的动态内存分配
 * 假设我们要为一个字符数组（一个有 20 个字符的字符串）分配内存，我们可以使用上面实例中的语法来为数组动态地分配内存，如下所示：

      char* pvalue  = NULL;   // 初始化为 null 的指针
      pvalue  = new char[20]; // 为变量请求内存

 * 要删除我们刚才创建的数组，语句如下：

      delete [] pvalue;        // 删除 pvalue 所指向的数组

 * 下面是 new 操作符的通用语法，可以为多维数组分配内存，如下所示：
 * #1 一维数组动态分配内存
 * 
 * 一维数组

    int *array=new int [m];// 动态分配,数组长度为 m
    delete [] array;//释放内存

 * 
 *
 * #2 二维数组动态分配空间
 * 
 * 二维数据
  
        int **array
        // 假定数组第一维长度为 m， 第二维长度为 n
        // 动态分配空间
        array = new int *[m];
        for( int i=0; i<m; i++ )
        {
            array[i] = new int [n]  ;
        }
        //释放
        for( int i=0; i<m; i++ )
        {
            delete [] array[i];
        }
        delete [] array;

 * 
 * #3 三维数组动态分配内存
 * 三维数组
 
        int ***array;
        // 假定数组第一维为 m， 第二维为 n， 第三维为h
        // 动态分配空间
        array = new int **[m];
        for( int i=0; i<m; i++ )
        {
            array[i] = new int *[n];
            for( int j=0; j<n; j++ )
            {
                array[i][j] = new int [h];
            }
        }
        //释放
        for( int i=0; i<m; i++ )
        {
            for( int j=0; j<n; j++ )
            {
                delete[] array[i][j];
            }
            delete[] array[i];
        }
        delete[] array;
*/

#include <iostream>
#include <ctime>
#define __mark 3

/**
 * #1 一维数组动态分配内存
*/
#if __mark == 1
int *getRandomNums(int);
void printNums(int *, int);

int main(void)
{
  // const int size = 5;
  // int *arr = new int [size]; // 动态分配，数组长度为size

  // // delete arr;
  // delete [] arr; // 释放内存

  int *nums = NULL;
  const int num = 4;
  nums = getRandomNums(num);

  // printNums(nums, num);
  // for (int i = 0; i < num; i++)
  // {
  //   int el = nums[i];
  //   std::cout << "nums[" << i << "] : " << el << std::endl;
  // }

  // delete[] nums;
  // delete nums;// 这两个什么区别？
  // std::cout << "------------delete----------------" << std::endl;
  // printNums(nums, num);

  // for (int i = 0; i < num; i++)
  // {
  //   int el = nums[i];
  //   std::cout << "nums[" << i << "] : " << el << std::endl;
  // }

  printf("-----------------end--------------\n");
  return 0;
}

int *getRandomNums(int num)
{
  srand((unsigned)time(NULL));

  // static int arr[num]; // 变长数组不能包含静态存储持续时间  error: storage size of 'arr' isn't constant

  int *arr = new int[num]; // 动态分配的数据从函数中返回不许加static？加了是什么意思；

  for (int i = 0; i < num; i++)
  {
    arr[i] = rand() % 100 + 1; // 1~100的随机数
  }

  printNums(arr, num);

  delete arr;
  // delete[] arr; // 释放内存
  // 释放过后看不出明显变化，而且就数组前4个元素取值异常，其他元素正常取到
  std::cout << "------------delete----------------" << std::endl;
  printNums(arr, num);

  return arr;
}

void printNums(int *arr, int size)
{
  for (int i = 0; i < size; i++)
  {
    int el = arr[i];
    std::cout << "nums[" << i << "] : " << el << std::endl;
  }
}

/**
 * #2 二维数组动态分配内存
*/
#elif __mark == 2
#include <ctime>
int **getRandomMap(int, int);
void printMap(int **, int, int);

int main(void)
{
  /**
  const int m = 2; // 第一维长度m 2
  const int n = 3; // 第二维长度n 3
  int **arr = new int *[m];
  for (int i = 0; i < m; i++)
  {
    arr[i] = new int[n];
  }

  // 释放
  for (int i = 0; i < m; i++)
  {
    delete[] arr[i];
  }

  delete[] arr;

  */

  const int x = 5;
  const int y = 10;
  int **map;
  map = getRandomMap(x, y);

  std::cout << "print map..." << std::endl;
  printMap(map, x, y);

  std::cout << "print map1..." << std::endl;
  int map1[2][2] = {0, 1, 1, 2};
  //  printMap(map1, 2, 2);//  error: cannot convert 'int (*)[2]' to 'int**'
  // printMap((int **)map1, 2, 2);

  printf("-----------------end--------------\n");
  return 0;
}

int **getRandomMap(int x, int y)
{
  srand((unsigned)time(NULL));
  // static int map[x][y];
  int **map = NULL;
  map = new int *[x];
  for (int i = 0; i < x; i++)
  {
    map[i] = new int[y];
  }

  for (int i = 0; i < x; i++)
  {
    for (int j = 0; j < y; j++)
    {
      map[i][j] = rand() % 6; // 0 ~ 5
      // int el = map[i][j];
      // std::cout << "map[" << i << "][" << j << "] : " << map[i][j] << std::endl;
    }
  }

  // 释放
  // for (int i = 0; i < x; i++)
  // {
  //   delete[] map[i];
  // }

  // delete[] map;

  return map;
}

void printMap(int **arr, int x, int y)
{
  for (int i = 0; i < x; i++)
  {
    for (int j = 0; j < y; j++)
    {
      // int el = arr[i][j]; // 可以取值
      int el = *(arr[i] + j); // 可以取值

      // int el = *((int *)arr + i * y + j);// 取值不正常
      // int el = ((int *)arr + i * y)[j];// 取值不正常

      std::cout.width(2);
      std::cout << el;

      // std::cout << el << " ";

      // std::cout << "map[" << i << "][" << j << "] : " << el << std::endl;
    }
    std::cout << "\n";
  }
  std::cout << std::endl;
}

/**
 * 三维数据动态分配内存
*/
#elif __mark == 3
#include <ctime>

int ***getRandomMap(int, int, int);

void printMap(int ***, int, int, int);

int main(void)
{
  /**
  int ***array;
  const int x = 2; // x为一维长度
  const int y = 3; // y为二维长度
  const int z = 4; // z为三维长度

  array = new int **[x];
  for (int i = 0; i < x; i++)
  {
    array[i] = new int *[y];
    for (int j = 0; j < y; j++)
    {
      array[i][j] = new int[z];
    }
  }

  // 释放空间
  for (int i = 0; i < x; i++)
  {
    for (int j = 0; j < y; j++)
    {
      delete[] array[i][j];
    }
    delete[] array[i];
  }
  delete[] array;
  */
  const int x = 5;
  const int y = 5;
  const int z = 5;
  int ***map;
  map = getRandomMap(x, y, z);
  printMap(map, x, y, z);

  printf("-----------------end-----------------\n");
  return 0;
}

int ***getRandomMap(int x, int y, int z)
{
  int ***map;
  map = new int **[x];
  for (int i = 0; i < x; i++)
  {
    map[i] = new int *[y];
    for (int j = 0; j < y; j++)
    {
      map[i][j] = new int[z];
    }
  }

  srand((unsigned)time(NULL));
  for (int i = 0; i < x; i++)
  {
    for (int j = 0; j < y; j++)
    {
      for (int k = 0; k < z; k++)
      {
        map[i][j][k] = rand() % 6; // 0~5的随机数
        // std::cout << "map[" << i << "][" << j << "][" << k << "] : " << std::endl;
      }
    }
  }

  return map;
}

void printMap(int ***map, int x, int y, int z)
{
  for (int i = 0; i < x; i++)
  {
    std::cout << "------------ i : " << i << " ------------" << std::endl;
    for (int j = 0; j < y; j++)
    {
      for (int k = 0; k < z; k++)
      {
        int el = map[i][j][k];
        std::cout.width(2);
        std::cout << el;
        // std::cout << "map[" << i << "][" << j << "][" << k << "] : " << std::endl;
      }
      std::cout << std::endl;
    }
  }
}

#endif